from PySide6.QtCore import Slot,Qt, Signal
from PySide6.QtSerialPort import QSerialPort, QSerialPortInfo
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout,
                               QGroupBox, QGridLayout, QLabel,
                               QComboBox, QPushButton, QTextEdit)


class MePage(QWidget):

    r_data_singal = Signal(str)

    def __init__(self, serial: QSerialPort, parent=None):
        super().__init__(parent)
        self.serial = serial
        self._setup_ui()
        self.serial.readyRead.connect(self.on_serial_read)

    def _setup_ui(self):
        self.setStyleSheet('background:#f8f4e8;')
        lay = QVBoxLayout(self)
        lay.addWidget(QLabel('我页面', alignment=Qt.AlignCenter))

        # 配置区
        g = QGroupBox('串口配置')
        grid = QGridLayout(g)
        self.port_cb = QComboBox()
        self.baud_cb = QComboBox()
        self.baud_cb.addItems(['9600', '19200', '38400', '57600', '115200'])
        self.baud_cb.setCurrentText('115200')
        self.data_cb = QComboBox()
        self.data_cb.addItems(['5', '6', '7', '8'])
        self.data_cb.setCurrentText('8')
        self.stop_cb = QComboBox()
        self.stop_cb.addItems(['1', '1.5', '2'])
        self.parity_cb = QComboBox()
        self.parity_cb.addItems(['无', '奇校验', '偶校验'])

        grid.addWidget(QLabel('串口:'), 0, 0)
        grid.addWidget(self.port_cb, 0, 1)
        grid.addWidget(QLabel('波特率:'), 1, 0)
        grid.addWidget(self.baud_cb, 1, 1)
        grid.addWidget(QLabel('数据位:'), 2, 0)
        grid.addWidget(self.data_cb, 2, 1)
        grid.addWidget(QLabel('停止位:'), 3, 0)
        grid.addWidget(self.stop_cb, 3, 1)
        grid.addWidget(QLabel('校验位:'), 4, 0)
        grid.addWidget(self.parity_cb, 4, 1)

        # 按钮
        bar = QHBoxLayout()
        self.refresh_btn = QPushButton('刷新串口')
        self.open_btn = QPushButton('打开串口')
        self.close_btn = QPushButton('关闭串口')
        self.close_btn.setEnabled(False)
        bar.addWidget(self.refresh_btn)
        bar.addWidget(self.open_btn)
        bar.addWidget(self.close_btn)
        bar.addStretch()
        grid.addLayout(bar, 5, 0, 1, 2)

        self.status_lbl = QLabel('串口未打开')
        grid.addWidget(self.status_lbl, 6, 0, 1, 2)
        lay.addWidget(g)

        # 接收区
        g2 = QGroupBox('接收数据')
        v2 = QVBoxLayout(g2)
        self.recv_edit = QTextEdit(readOnly=True)
        v2.addWidget(self.recv_edit)
        lay.addWidget(g2)
        lay.addStretch()

        # 信号
        self.refresh_btn.clicked.connect(self.refresh_ports)
        self.open_btn.clicked.connect(self.open_serial)
        self.close_btn.clicked.connect(self.close_serial)
        self.refresh_ports()

    # ---------- 槽 ----------
    @Slot()
    def refresh_ports(self):
        self.port_cb.clear()
        ports = QSerialPortInfo.availablePorts()
        for p in ports:
            self.port_cb.addItem(f'{p.portName()} - {p.description()}')
        if not ports:
            self.port_cb.addItem('未检测到串口')
            self.open_btn.setEnabled(False)
        else:
            self.open_btn.setEnabled(True)

    @Slot()
    def open_serial(self):
        if '未检测到' in self.port_cb.currentText():
            return
        name = self.port_cb.currentText().split(' - ')[0]
        self.serial.setPortName(name)
        self.serial.setBaudRate(int(self.baud_cb.currentText()))
        self.serial.setDataBits(getattr(QSerialPort, f'Data{self.data_cb.currentText()}'))
        self.serial.setStopBits({'1': QSerialPort.OneStop,
                                 '1.5': QSerialPort.OneAndHalfStop,
                                 '2': QSerialPort.TwoStop}[self.stop_cb.currentText()])
        self.serial.setParity({'无': QSerialPort.NoParity,
                               '奇校验': QSerialPort.OddParity,
                               '偶校验': QSerialPort.EvenParity}[self.parity_cb.currentText()])

        if self.serial.open(QSerialPort.ReadWrite):
            self.status_lbl.setText(f'串口已打开 - {name}')
            self.open_btn.setEnabled(False)
            self.close_btn.setEnabled(True)
            self.port_cb.setEnabled(False)
        else:
            self.status_lbl.setText(f'打开失败: {self.serial.errorString()}')

    @Slot()
    def close_serial(self):
        self.serial.close()
        self.status_lbl.setText('串口已关闭')
        self.open_btn.setEnabled(True)
        self.close_btn.setEnabled(False)
        self.port_cb.setEnabled(True)

    @Slot()
    def on_serial_read(self):
        if self.serial.isOpen():
            data = self.serial.readAll()
            txt = data.data().decode('utf-8', errors='ignore')
            self.recv_edit.append(f'接收: {txt}')
            if len(txt) != 0:
                self.r_data_singal.emit(txt)
